package com.kaguya.visitor;

import java.util.LinkedList;

/**
 * 访问者模式：
 * 目的：将数据结构和数据操作分离，根据访问者的不同改变具体的数据操作，且不改变原有的结构。
 * （例如别人来病房探病，不同关系程度的来访者带的东西程度不一样，例如朋友可能带些零食和你聊聊天，家人会带些水果或者炖些补品）
 * 优点：扩展性高，适用于数据结构相对稳定的系统，适用于报表，UI，拦截器过滤器，符合单一职责
 * 缺点：公布细节，违反迪米特原则，不符合依赖倒置原则，要变更具体细节比较困难
 * 主要原理：在被访问类里提供一个 接待 访问者 的接口
 * 主要应用场景：需要对一个结构的对象进行很多不同且不相关联的操作，可以选用该模式，同时可搭配观察者模式或责任链模式，让整体架构更加灵活
 */
public class Test {
    public static void main(String[] args) {
        // 1.创建一个访问者结构，管理所有的访问者
        ObjectStructure objManager = new ObjectStructure();
        // 2.创建对应的访问者，并交给访问者结构管理
        GroupLeader groupLeader = new GroupLeader();
        Manager manager = new Manager();
        Financial financial = new Financial();

        objManager.attachVisitor(groupLeader);
        objManager.attachVisitor(manager);
        objManager.attachVisitor(financial);

        // 3.创建具体的行为，访问者结构根据访问者和行为去执行指定操作（双分派：由访问者和行为决定执行的操作）
        System.out.println("pass---------------------");
        PassAction passAction = new PassAction();
        objManager.displayAll(passAction);

        // 公司人员变动，审批不经过组长
        objManager.detachVisitor(groupLeader);

        System.out.println("fail---------------------");
        FailAction failAction = new FailAction();
        objManager.displayAll(failAction);

        System.out.println("return-------------------");
        ReturnAction returnAction = new ReturnAction();
        objManager.displayAll(returnAction);
    }
}

/**
 * 抽象行为 审核行为
 */
abstract class AuditAction {

    /**
     * 组长审核
     */
    abstract void groupLeaderAudit();

    /**
     * 经理审核
     */
    abstract void managerAudit();

    /**
     * 财务审核
     */
    abstract void financialAudit();
}

/**
 * 审核通过
 */
class PassAction extends AuditAction {

    @Override
    void groupLeaderAudit() {
        System.out.println("组长同意该审批");
    }

    @Override
    void managerAudit() {
        System.out.println("经理同意该审批");
    }

    @Override
    void financialAudit() {
        System.out.println("财务同意该审批");
    }
}

/**
 * 审核失败
 */
class FailAction extends AuditAction {

    @Override
    void groupLeaderAudit() {
        System.out.println("组长拒绝该审批");
    }

    @Override
    void managerAudit() {
        System.out.println("经理拒绝该审批");
    }

    @Override
    void financialAudit() {
        System.out.println("财务拒绝该审批");
    }
}

/**
 * 审核退回
 */
class ReturnAction extends AuditAction {

    @Override
    void groupLeaderAudit() {
        System.out.println("组长退回该审批");
    }

    @Override
    void managerAudit() {
        System.out.println("经理退回该审批");
    }

    @Override
    void financialAudit() {
        System.out.println("财务退回该审批");
    }
}

/**
 * 抽象访问者
 */
abstract class Visitor {
    /**
     * 对外提供的访问方法
     * @param action
     */
    abstract void accept(AuditAction action);
}

/**
 * 访问者1 组长
 */
class GroupLeader extends Visitor {

    @Override
    void accept(AuditAction action) {
        action.groupLeaderAudit();
    }
}

/**
 * 访问者2 经理
 */
class Manager extends Visitor {

    @Override
    void accept(AuditAction action) {
        action.managerAudit();
    }
}

/**
 * 访问者3 财务
 */
class Financial extends Visitor {

    @Override
    void accept(AuditAction action) {
        action.financialAudit();
    }
}

/**
 * 数据结构，维护所有的访问者
 */
class ObjectStructure {
    /**
     * 保存所有的访问者，并提供新增删除 查看方法
     */
    private LinkedList<Visitor> visitors = new LinkedList<>();

    /**
     * 新增一个访问者
     * @param visitor
     * @return
     */
    public boolean attachVisitor(Visitor visitor) {
        return visitors.add(visitor);
    }

    /**
     * 删除指定访问者
     * @param visitor
     * @return
     */
    public boolean detachVisitor(Visitor visitor) {
        return visitors.remove(visitor);
    }

    /**
     * 遍历所有访问者行为
     */
    public void displayAll(AuditAction action) {
        for (Visitor v : visitors) {
            v.accept(action);
        }
    }
}